#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "DigitalTempSensor.h"
#include "AnalogTempSensor.h"
#include "SensorChannels.h"
#include "IntTimeSensor.h"
#include "StateMachine.h"
#include "Hardware.h"
#include "package.h"
#include "usart.h"
#include "tick.h"


#undef TRACE_LEVEL
#undef TRACE_TITLE
#undef TRACE_TITLE
#define TRACE_LEVEL TRACE_LEVEL_DEBUG
#define TRACE_NAME  TRACE_NAME_DISABLE
#define TRACE_TITLE "CHANNEL"
#include "trace.h"


static void ChannelPowerIOInit(int channel);
static void ChannelPowerIODeInit(int channel);
static void ChannelExtIntCallback(int channel, int IOLevel);
static void ChannelFreqIntCallback(int channel, int IOLevel);
static void Channel5VPowerCtrl(int channel, FunctionalState Enable);
static void Channel3V3PowerCtrl(int channel, FunctionalState Enable);


// Temperature Sensor type
typedef enum {
	TSENSOR_DIGITAL_DS18B20,
	TSENSOR_ANALOG_PT1000,
	TSENSOR_NC,
} TempSensorType_t;

// Sensor channel type
typedef struct {
	int Enable;
	int isTimeDirty;
	int TimeLock;
	uint32_t time;
	uint32_t count;
	// int IOLevel;
	// void *handle;
	ChannelMode_t Mode;
	TempSensorType_t TempSensorType; 
} SensorChannel_t;


static __inline int isChannelIllegal(int channel) {
	return (channel >= PHYSENSOR_CHANNELS) ? TRUE : FALSE;
}

const SensorChannelHw_t channelHwInfo[PHYSENSOR_CHANNELS] = {
	{{CH1_POWER_CTRL_PORT, CH1_POWER_CTRL_PIN}, {NULL, NULL}, {CH1_PULLUP_CTRL_PORT, CH1_PULLUP_CTRL_PIN}, {CH1_IOA_PORT, CH1_IOA_PIN}, {CH1_IOB_PORT, CH1_IOB_PIN}},
	{{CH2_POWER_CTRL_PORT, CH2_POWER_CTRL_PIN}, {NULL, NULL}, {CH2_PULLUP_CTRL_PORT, CH2_PULLUP_CTRL_PIN}, {CH2_IOA_PORT, CH2_IOA_PIN}, {CH2_IOB_PORT, CH2_IOB_PIN}},
	{{CH3_POWER_CTRL_PORT, CH3_POWER_CTRL_PIN}, {NULL, NULL}, {CH3_PULLUP_CTRL_PORT, CH3_PULLUP_CTRL_PIN}, {CH3_IOA_PORT, CH3_IOA_PIN}, {CH3_IOB_PORT, CH3_IOB_PIN}},
};

// channel state
static SensorChannel_t PhySensorChannels[PHYSENSOR_CHANNELS];


int OpenChannel(int channel, ChannelMode_t mode) {
	SensorChannel_t *Ch;
	const SensorChannelHw_t *Hw;
	
	TRACE_DEBUG("Open channel[%d] ", channel);
	
	if (isChannelIllegal(channel) == TRUE) {
		TRACE_DEBUG_WP("[FAILED][INDEX=%d]", channel);
		return -1;
	}
	
	Ch = &PhySensorChannels[channel];
	Hw = &channelHwInfo[channel];
	
	if(Ch->Enable) {
		CloseChannel(channel);
	}
	
	switch(mode) {
	case CHANNEL_TEMP:
		TRACE_DEBUG_WP("[TEMP]");
		// try to open digital temperature sensor first
		Ch->Mode = CHANNEL_TEMP;
	
		// Enable Channel 3V3 Power
		ChannelPowerIOInit(channel);
		Channel3V3PowerCtrl(channel, ENABLE);
		
		if(OpenDigitalTemperatureSensor(channel, Hw, 800) != 0) {
			// Then we try to open analog temperature sensor
			// We do not need 3v3 on analog temperature
			ChannelPowerIODeInit(channel);
			
			if(OpenAnalogTemperatureSensor(channel, Hw, 50) != 0) {
				Ch->Enable = FALSE;
				Ch->TempSensorType = TSENSOR_NC;
				TRACE_DEBUG_WP("[NOT CONNECTED]");
				return -1;
			} else {
				// We hava Analog temperature sensor here
				Ch->Enable = TRUE;
				Ch->TempSensorType = TSENSOR_ANALOG_PT1000;
				TRACE_DEBUG_WP("[ANALOG PT1000]");
				return 0;
			}
		} else {
			// We hava digital temperature sensor here
			Ch->Enable = TRUE;
			Ch->TempSensorType = TSENSOR_DIGITAL_DS18B20;
			TRACE_DEBUG_WP("[DIGITAL DS18B20]");
			return 0;
		}
	case CHANNEL_TIME:
		TRACE_DEBUG_WP("[TIME]");
	
		// Enable the 3V3 for time sensor
		ChannelPowerIOInit(channel);
		Channel3V3PowerCtrl(channel, ENABLE);
	
		if(OpenTimerSensor(channel, Hw, ChannelExtIntCallback) != 0) {
			TRACE_DEBUG_WP("[FAILED]");
			return -1;
		} else {
			Ch->Mode = CHANNEL_TIME;
			Ch->isTimeDirty = FALSE;
			Ch->TimeLock = FALSE;
			Ch->time = 0;
			Ch->Enable = TRUE;
			TRACE_DEBUG_WP("[PASSED]");
			return 0;
		}
	case CHANNEL_FREQ:
		TRACE_DEBUG_WP("[FREQ]");
		
		// Enable the 3V3 for frequency sensor
		ChannelPowerIOInit(channel);
		Channel3V3PowerCtrl(channel, ENABLE);
	
		if(OpenTimerSensor(channel, Hw, ChannelFreqIntCallback) != 0) {
			TRACE_DEBUG_WP("[FAILED]");
			return -1;
		} else {
			Ch->Mode = CHANNEL_FREQ;
			Ch->count = 0;
			Ch->time = get_tick_count();
			Ch->Enable = TRUE;
			TRACE_DEBUG_WP("[PASSED]");
			return 0;
		}
	default:
		return -1;
	}
}

int isChannelEnable(int channel) {
	if (isChannelIllegal(channel) == TRUE) {
		return -1;
	}
	return PhySensorChannels[channel].Enable;
}

int CloseChannel(int channel) {
	SensorChannel_t *Ch;
	const SensorChannelHw_t *Hw;
	
	TRACE_DEBUG("Close channel[%d] ", channel);
	
	if (isChannelIllegal(channel) == TRUE) {
		TRACE_DEBUG_WP("[FAILED][INDEX=%d]", channel);
		return -1;
	}
	Ch = &PhySensorChannels[channel];
	Hw = &channelHwInfo[channel];
	
	// disable the channel 3v3 and 5v power
	ChannelPowerIODeInit(channel);
	
	switch(Ch->Mode) {
	case CHANNEL_TEMP:
		switch(Ch->TempSensorType) {
		case TSENSOR_ANALOG_PT1000:
			CloseAnalogTemperatureSensor(channel, Hw);
		break;
		case TSENSOR_DIGITAL_DS18B20:
			CloseDigitalTemperatureSensor(channel, Hw);
		break;
		case TSENSOR_NC:
		break;
		}
	break;
	case CHANNEL_TIME:
	case CHANNEL_FREQ:
		// Frequency also uses timer driver for now
		CloseTimerSensor(channel, Hw);
	break;
	case CHANNEL_HYGR:
	break;
	}
	
	Ch->Enable = FALSE;
	Ch->Mode = CHANNEL_TEMP;
	Ch->TempSensorType = TSENSOR_NC;
	TRACE_DEBUG_WP("[PASSED]");
	return 0;
}

void OutputChannelData(int channel) {
	SensorChannel_t *Ch;
	uint16_t buffer[4];
	uint32_t timeCache;
	uint32_t Count;
	int IOLevel;
	
	if (isChannelIllegal(channel) == TRUE) {
		return;
	}
	
	Ch = &PhySensorChannels[channel];
	if(Ch->Enable == FALSE) {
		return;
	}
	
	switch(Ch->Mode) {
	case CHANNEL_TEMP:
		switch(Ch->TempSensorType) {
		case TSENSOR_DIGITAL_DS18B20:
			if(ReadDigitalTemperatureSensor(channel, &buffer[1])) {
				buffer[0] = (0 << 8) | channel;
				buffer[2] = 0;
				// buffer[0] = channel number and sensor type (digital<1> or analog<0>)
				// buffer[1] = temperature value * 16
				// buffer[2] = dummy value
				TRACE_DEBUG("DIGITAL_TEMP_DATA[0x%x][0x%x][0x%x]", buffer[0], buffer[1], buffer[2]);
				WritePackage(PKG_TEMP_DATA, get_tick_count(), buffer, 3);
			}
		break;
		case TSENSOR_ANALOG_PT1000:
			if(ReadAnalogTemperatureSensor(channel, &buffer[1], &buffer[2])) {
				buffer[0] = (1 << 8) | channel;
				// buffer[0] = channel number and sensor type (digital<1> or analog<0>)
				// buffer[1] = ADC volt value 1
				// buffer[2] = ADC volt value 2
				TRACE_DEBUG("ANALOG_TEMP_DATA[0x%x][0x%x][0x%x]", buffer[0], buffer[1], buffer[2]);
				WritePackage(PKG_TEMP_DATA, get_tick_count(), buffer, 3);
			}
		break;
		case TSENSOR_NC:
		break;
		}
	break;
	case CHANNEL_TIME:
		if(PhySensorChannels[channel].isTimeDirty) {
			
			PhySensorChannels[channel].TimeLock = TRUE;
			PhySensorChannels[channel].isTimeDirty = FALSE;
			timeCache = PhySensorChannels[channel].time;
// 			IOLevel = PhySensorChannels[channel].IOLevel ? 1 : 0;
			// FIXME: Bug Here, always return 0
			IOLevel = 0;
			PhySensorChannels[channel].TimeLock = FALSE;
			
			buffer[0] = (IOLevel << 8) | channel;
			// buffer[0] = IO-level<0,1> and channel number
			TRACE_DEBUG("TIME_DATA[0x%x][0x%x]", timeCache, buffer[0]);	
			WritePackage(PKG_TIME_DATA, timeCache, buffer, 1);
		}
		break;
	case CHANNEL_FREQ:
		timeCache = get_tick_count();
		if( (timeCache - PhySensorChannels[channel].time) >= 1000) {
			Count = PhySensorChannels[channel].count;
			PhySensorChannels[channel].count = 0;
			PhySensorChannels[channel].time = timeCache;
			// Count equrts frequency
			buffer[0] = channel;
			buffer[1] = (uint16_t)(Count & 0xFFFF);
			buffer[2] = (uint16_t)((Count >> 16) & 0xFFFF);
			TRACE_DEBUG("FREQ_DATA[%d]", Count);
			WritePackage(PKG_FREQ_DATA, timeCache, buffer, 3);		
		}
	break;
	case CHANNEL_HYGR:
	break;
	}
}

int SetTemperatureSensorReadPeriodInMillisecond(int channel, int millisecond) {
	SensorChannel_t *Ch;
	int error = 0;
	
	if (isChannelIllegal(channel) == TRUE) {
		return -1;
	}
	
	Ch = &PhySensorChannels[channel];
	if(Ch->Enable == FALSE)
		return -1;
	
	if(Ch->Mode != CHANNEL_TEMP)
		return -1;

	switch(Ch->TempSensorType) {
	case TSENSOR_DIGITAL_DS18B20:
		if(SetDigitalTemperatureSensorReadPeriodInMs(channel, millisecond) != 0)
			error = -1;
	break;
	case TSENSOR_ANALOG_PT1000:
		if(SetAnalogTemperatureSensorReadPeriodInMs(channel, millisecond) != 0)
			error = -1;
	break;
	case TSENSOR_NC:
		error = -1;
	break;
	}
	return error;
}

// For Timer Sensor channel
static void ChannelExtIntCallback(int channel, int IOLevel) {
	if (PhySensorChannels[channel].TimeLock == FALSE) {
		PhySensorChannels[channel].time = get_tick_count();
		// PhySensorChannels[channel].IOLevel = IOLevel;
		PhySensorChannels[channel].isTimeDirty = TRUE;
	}
}

// For Frequency channel
static void ChannelFreqIntCallback(int channel, int IOLevel) {
	PhySensorChannels[channel].count ++;
}


static void Channel3V3PowerCtrl(int channel, FunctionalState Enable) {
	if(isChannelIllegal(channel) == TRUE) {
		return;
	}
	
	if(channelHwInfo[channel].Power3V3Ctrl.Port == NULL)
		return;
	
	// for PNP control logic
	if(Enable) {
		GPIO_ResetBits(channelHwInfo[channel].Power3V3Ctrl.Port,
			channelHwInfo[channel].Power3V3Ctrl.PinMask);
	} else {
		GPIO_SetBits(channelHwInfo[channel].Power3V3Ctrl.Port,
			channelHwInfo[channel].Power3V3Ctrl.PinMask);
	}
}

static void Channel5VPowerCtrl(int channel, FunctionalState Enable) {
	if(channelHwInfo[channel].Power5VCtrl.Port == NULL)
		return;
	
	// for PNP control logic
	if(Enable) {
		GPIO_ResetBits(channelHwInfo[channel].Power5VCtrl.Port,
			channelHwInfo[channel].Power5VCtrl.PinMask);
	} else {
		GPIO_SetBits(channelHwInfo[channel].Power3V3Ctrl.Port,
			channelHwInfo[channel].Power5VCtrl.PinMask);
	}
}

static void ChannelPowerIOInit(int channel) {
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	
	if(channelHwInfo[channel].Power3V3Ctrl.Port) {
		GPIO_InitStructure.GPIO_Pin = channelHwInfo[channel].Power3V3Ctrl.PinMask;
		GPIO_Init(channelHwInfo[channel].Power3V3Ctrl.Port, &GPIO_InitStructure);
		
		// Disable the 3V3 Power as start
		Channel3V3PowerCtrl(channel, DISABLE);
	}
	
	if(channelHwInfo[channel].Power5VCtrl.Port) {
		GPIO_InitStructure.GPIO_Pin = channelHwInfo[channel].Power5VCtrl.PinMask;
		GPIO_Init(channelHwInfo[channel].Power5VCtrl.Port, &GPIO_InitStructure);
		
		// Disable the 5V Power as start
		Channel5VPowerCtrl(channel, DISABLE);
	}
}

static void ChannelPowerIODeInit(int channel) {
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	
	if(channelHwInfo[channel].Power3V3Ctrl.Port) {
		GPIO_InitStructure.GPIO_Pin = channelHwInfo[channel].Power3V3Ctrl.PinMask;
		GPIO_Init(channelHwInfo[channel].Power3V3Ctrl.Port, &GPIO_InitStructure);
	}
	
	if(channelHwInfo[channel].Power5VCtrl.Port) {
		GPIO_InitStructure.GPIO_Pin = channelHwInfo[channel].Power5VCtrl.PinMask;
		GPIO_Init(channelHwInfo[channel].Power5VCtrl.Port, &GPIO_InitStructure);
	}
}


#if (0)
int ChannelMain() {
// 	ChannelPowerIOInit(0);
// 	Channel3V3PowerCtrl(0, ENABLE);
// 	Channel3V3PowerCtrl(0, DISABLE);
// 	Channel3V3PowerCtrl(0, ENABLE);
// 	ChannelPowerIODeInit(0);
// 	
// 	ChannelPowerIOInit(1);
// 	Channel3V3PowerCtrl(1, ENABLE);
// 	Channel3V3PowerCtrl(1, DISABLE);
// 	Channel3V3PowerCtrl(1, ENABLE);
// 	ChannelPowerIODeInit(1);
// 	
// 	ChannelPowerIOInit(2);
// 	Channel3V3PowerCtrl(2, ENABLE);
// 	Channel3V3PowerCtrl(2, DISABLE);
// 	Channel3V3PowerCtrl(2, ENABLE);
// 	ChannelPowerIODeInit(2);
	
	ChannelPowerIOInit(0);
 	Channel3V3PowerCtrl(0, ENABLE);
	ChannelPowerIOInit(1);
 	Channel3V3PowerCtrl(1, ENABLE);
	ChannelPowerIOInit(2);
 	Channel3V3PowerCtrl(2, ENABLE);
	DigitalSensorMain();
	while (1);
	return 0;
}
#endif




